/*
 * @Descripttion: 命令测试模块tpm2_utils. 实现根据控制台输入命令字符串生成命令的二进制流
 * @version:
 * @Author:
 * @Date:
 * @LastEditors:
 * @LastEditTime: 2021-07-15 10:27:47
 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "data_type.h"
#include "errno.h"
#include "alloc.h"
#include "list.h"
#include "attrlist.h"
#include "memfunc.h"
#include "basefunc.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "memdb.h"
#include "message.h"
#include "ex_module.h"
#include "channel.h"
#include "sys_func.h"

#include "tpm2_value.h"
#include "tpm2_base_structs.h"
#include "tpm2_structure.h"

#include "tpm2_global.h"
#include "tpm2_command.h"
#include "vtcm_alg.h"

#include "tpm2_utils.h"

static BYTE Buf[DIGEST_SIZE * 32];
static BYTE Output[DIGEST_SIZE * 32];

void *curr_recv_msg = NULL;

static CHANNEL *tpm2_caller;

// Ex CA Module

void *tpm2_auto_build_outputmsg(char *out_line, void *active_msg)
{

    RECORD(TPM2_UTILS, OUTPUT) * output_para;
    int offset = 0;
    int ret;
    int i = 0;
    void *send_msg;
    BYTE *out_param;

    output_para = Talloc0(sizeof(*output_para));
    if (output_para == NULL)
        return NULL;

    do
    {
        out_param = &Output[DIGEST_SIZE * 2 * i];
        Memset(out_param, 0, DIGEST_SIZE * 2);
        ret = Getfiledfromstr(out_param, out_line + offset, ' ', DIGEST_SIZE * 2);
        if (ret > 0)
        {
            i++;
            offset += ret + 1;
        }
    } while (ret > 0);

    // Build output para message

    output_para->param_num = i;
    if (i > 0)
    {
        output_para->params = Talloc0(DIGEST_SIZE * 2 * output_para->param_num);
        Memcpy(output_para->params, Output, DIGEST_SIZE * 2 * output_para->param_num);
    }
    send_msg = message_create(TYPE_PAIR(TPM2_UTILS, OUTPUT), active_msg);
    message_add_record(send_msg, output_para);
    return send_msg;
}

int proc_tpm2utils_input(void *sub_proc, void *recv_msg);

// proceed the tpm2 command
int proc_tpm2utils_GetRandom(void *sub_proc, void *para);
int proc_tpm2utils_PCR_Read(void *sub_proc, void *para);
int proc_tpm2utils_PCR_Extend(void *sub_proc, void *para);
int proc_tpm2utils_Object_CreatePrimary(void *sub_proc, void *para);
int proc_tpm2utils_Object_Create(void *sub_proc, void *para);
int tpm2utils_transmit(int in_len, BYTE *in, int *out_len, BYTE *out);
// 将请求命令输入到二进制文件中
int tpm2utils_bytes2binfile(int *ret, char *cmdfilename);
//  读取命令返回的二进制文件
int tpm2utils_binfile2bytes(int *ret, char *responsefilename);
// 调用ibm tpm2 模拟器,发送执行命令，并将返回结果。
int tpm2utils_ex_ibmtpm2_emulator(int *ret, char *shellcmd, char *cmdfilename, char *responsefilename);

int tpm2_utils_init(void *sub_proc, void *para)
{
    int ret;
    struct tpm2_utils_init_para *init_para = para;
    if (para == NULL)
        return -EINVAL;
    tpm2_caller = channel_find(init_para->channel_name);

    if (tpm2_caller == NULL)
    {
        print_cubeerr("tpm2_utils's tpm2 channel does not exist!,enter no tpm2 running state!\n");
        return 0;
    }

    return 0;
}
int TSS_gennonce(unsigned char *nonce)
{
    return RAND_bytes(nonce, SM3_256_DIGEST_SIZE);
}
int tpm2_utils_start(void *sub_proc, void *para)
{
    printf("tpm2_utils module start!\n");
    int ret;
    int retval;
    void *recv_msg;
    void *send_msg;
    void *context;
    void *sock;
    BYTE uuid[DIGEST_SIZE];
    int i;
    int type;
    int subtype;

    //	print_cubeaudit("begin proc tpm2_utils \n");

    //    ret=proc_tpm2utils_start(sub_proc,para);
    //    if(ret<0)
    //        return ret;

    while (1)
    {
        usleep(time_val.tv_usec);
        ret = ex_module_recvmsg(sub_proc, &recv_msg);
        if (ret < 0)
            continue;
        if (recv_msg == NULL)
            continue;

        type = message_get_type(recv_msg);
        subtype = message_get_subtype(recv_msg);
        if ((type == TYPE(TPM2_UTILS)) && (subtype == SUBTYPE(TPM2_UTILS, INPUT)))
        {
            ret = proc_tpm2utils_input(sub_proc, recv_msg);
        }
    }

    return 0;
};

int proc_tpm2utils_input(void *sub_proc, void *recv_msg)
{
    int ret = 0;
    int cmd_run = 0;

    struct tpm2_utils_input *input_para;
    ret = message_get_record(recv_msg, &input_para, 0);

    if (ret < 0)
        return -EINVAL;

    if (input_para->param_num < 1)
    {
        print_cubeerr("wrong command format! should be %s [cmd] [para] ...\n", "main_proc");
        return -EINVAL;
    }
    curr_recv_msg = recv_msg;
    if (tpm2_caller != NULL)
    {

        cmd_run = 1;
        if (strcmp(input_para->params, "extend") == 0)
        {
            ret = proc_tpm2utils_PCR_Extend(sub_proc, input_para);
        }
        else if (strcmp(input_para->params, "pcrread") == 0)
        {
            ret = proc_tpm2utils_PCR_read(sub_proc, input_para);
        }
        else if (strcmp(input_para->params, "getrandom") == 0)
        {
            ret = proc_tpm2utils_getRandom(sub_proc, input_para);
        }
        else if (strcmp(input_para->params, "createPrimary") == 0)
        {
            ret = proc_tpm2utils_Object_CreatePrimary(sub_proc, input_para);
        }
        else if (strcmp(input_para->params, "create") == 0)
        {
            ret = proc_tpm2utils_Object_Create(sub_proc, input_para);
        }
        else
        {
            cmd_run = 0;
        }
    }

    if (cmd_run == 0)
    // run external command
    {

        curr_recv_msg = NULL;
        return ret;
    }
}

int proc_tpm2utils_getRandom(void *sub_proc, void *para)
{
    int outlen;
    int i = 0;
    int ret = 0;
    void *tpm2_template;
    int reqNum;
    int is_ibm_emulator = 0;
    RECORD(TPM2_IN, GetRandom) * tpm2_input;
    RECORD(TPM2_OUT, GetRandom) * tpm2_output;
    tpm2_input = Talloc0(sizeof(*tpm2_input));
    if (tpm2_input == NULL)
        return -ENOMEM;
    tpm2_output = Talloc0(sizeof(*tpm2_output));
    if (tpm2_output == NULL)
        return -ENOMEM;

    struct tpm2_utils_input *input_para = para; //定义输入参数
    char *index_para;
    char *value_para;
    // 封装输入参数
    if ((input_para->param_num > 0) && (input_para->param_num % 2 == 1))
    {
        for (i = 1; i < input_para->param_num; i += 2)
        {
            index_para = input_para->params + i * DIGEST_SIZE;
            value_para = index_para + DIGEST_SIZE; // input_para->params==getrandom   index_para=-gn   value_para=2
            if (!Strcmp("-ibm", index_para))       // in:  getrandom -ibm 0 -gn 08
            {
                sscanf(value_para, "%u", &is_ibm_emulator); // -ibm ： 对应是否调用ibm模拟器，默认为0，false。调用为 1 ，true。
            }
            else if (!Strcmp("-gn", index_para)) // in:  getrandom -ibm 0 -gn 08
            {
                sscanf(value_para, "%x", &reqNum); //将对应值参数 value_para 赋值给 reqNum，即 命令 getRandom 请求随机数 长度 , 此处将 value_para 转换为16进制
            }
            else
            {
                printf("Error cmd format! should be %s -gn getnum", input_para->params);
                return -EINVAL;
            }
        }
    }

    tpm2_input->tag = TPM_ST_NO_SESSIONS;
    tpm2_input->commandCode = TPM_CC_GetRandom;
    tpm2_input->bytesRequested = reqNum;
    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_IN, GetRandom));
    if (tpm2_template == NULL)
        return -EINVAL;
    tpm2_input->commandSize = sizeof(*tpm2_input);
    ret = struct_2_blob(tpm2_input, Buf, tpm2_template);
    if (ret < 0)
        return ret;
    printf("Send command for getRandom:\n");
    print_bin_data(Buf, ret, 16);

    // 是否调用ibm tpm2 模拟器，默认为 0 ，false。
    if (is_ibm_emulator)
    {
        // 调用ibm tpm2 模拟器执行请求命令。 将请求命令输入到二进制文件中。二进制文件默认生成在/cube-tpm2/instance/tpm2_utils目录中
        outlen = tpm2utils_ex_ibmtpm2_emulator(ret, "/root/centoscloud/cube-tpm2/instance/tpm2_utils/tpm2_send_getrandom_cmd.sh", "tpm2_cmd_getrandom.bin", "tpm2_response_getrandom.bin");
    }
    else
    {
        // 调用自己的 tpm2 模拟器执行请求命令。
        ret = tpm2utils_transmit(tpm2_input->commandSize, Buf, &outlen, Buf);
    }

    if (ret < 0)
        return ret;
    printf("Receive  output is:\n");
    print_bin_data(Buf, outlen, 16);

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, GetRandom));
    ret = blob_2_struct(Buf, tpm2_output, tpm2_template);
    if (ret < 0)
        return ret;

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, GetRandom));
    struct_read_elem_text("randomBytes.b.buffer", tpm2_output, Output, tpm2_template);

    sprintf(Buf, "%d %d %s\n", tpm2_output->responseCode, tpm2_output->randomBytes.b.size, Output);
    printf("Output para: %s\n", Buf);
    void *send_msg = tpm2_auto_build_outputmsg(Buf, curr_recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;
}

int proc_tpm2utils_PCR_Extend(void *sub_proc, void *para)
{
    int outlen;
    int i = 0;
    int ret = 0;
    int cmdsize = 0;
    int pcrIndex;
    char *message = NULL;
    void *tpm2_template;
    RECORD(TPM2_IN, PCR_Extend) * tpm2_input;
    RECORD(TPM2_OUT, PCR_Extend) * tpm2_output;
    tpm2_input = Talloc0(sizeof(*tpm2_input));
    if (tpm2_input == NULL)
        return -ENOMEM;
    tpm2_output = Talloc0(sizeof(*tpm2_output));
    if (tpm2_output == NULL)
        return -ENOMEM;

    struct tpm2_utils_input *input_para = para; //定义输入参数
    char *index_para;
    char *value_para;
    if ((input_para->param_num > 0) && (input_para->param_num % 2 == 1))
    {
        for (i = 1; i < input_para->param_num; i += 2)
        {
            index_para = input_para->params + i * DIGEST_SIZE;
            value_para = index_para + DIGEST_SIZE; // input_para->params==extend   index_para=-ix   value_para=2 ？？
            if (!Strcmp("-ix", index_para))        // in: extend -ix 2 -ic aaaa
            {
                sscanf(value_para, "%x", &pcrIndex); // tpm2_input->pcrIndex未定义？
            }
            else if (!Strcmp("-ic", index_para))
            {
                message = value_para;
            }
            else
            {
                printf("Error cmd format! should be %s -ix pcrindex -wf pcrfile", input_para->params);
                return -EINVAL;
            }
        }
    }

    tpm2_input->tag = TPM_ST_SESSIONS;
    tpm2_input->commandCode = TPM_CC_PCR_Extend;
    tpm2_input->pcrHandle = pcrIndex;
    tpm2_input->digests.count = 1;
    tpm2_input->digests.digests = Talloc0(sizeof(TPM2B_DIGEST) * tpm2_input->digests.count);
    tpm2_input->digests.digests->b.buffer = Talloc0(sizeof(TPM2B_DIGEST) * tpm2_input->digests.count);
    tpm2_input->digests.digests[0].b.size = sizeof(*message);
    tpm2_input->digests.digests[0].b.buffer = Talloc0(tpm2_input->digests.digests[0].b.size);
    Memset(tpm2_input->digests.digests[0].b.buffer, (int)(*message), tpm2_input->digests.digests[0].b.size); //把数据S写入缓冲区
    // tpm2_input->digests.digests[0].b.buffer = message;

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_IN, PCR_Extend));
    if (tpm2_template == NULL)
        return -EINVAL;
    tpm2_input->commandSize = sizeof(*tpm2_input);
    cmdsize = struct_2_blob(tpm2_input, Buf, tpm2_template); //?将命令转化为2进制格式？ Buf是个缓冲区 用来存放什么
    if (cmdsize < 0)
        return cmdsize;
    tpm2_input->commandSize = cmdsize;
    *(int *)(Buf + sizeof(tpm2_input->tag)) = htonl(cmdsize); // htonl()的作用是什么？将主机字节顺序转换为网络字节顺序
                                                              //   	cmdsize = struct_2_blob(tpm2_input,Buf,tpm2_template);
                                                              //  	if(cmdsize<0)
                                                              //   		return cmdsize;
    printf("Send command for PCR_Extend:\n");
    print_bin_data(Buf, cmdsize, 8);
    ret = tpm2utils_transmit(cmdsize, Buf, &outlen, Buf);
    if (ret < 0)
        return ret;
    printf("Receive  output is:\n");
    print_bin_data(Buf, outlen, 8);
    return ret;
}

int proc_tpm2utils_PCR_read(void *sub_proc, void *para)
{
    int outlen;
    int i = 0;
    int ret = 0;
    int cmdsize = 0;
    int pcrIndex;
    void *tpm2_template;
    char *pcrfile;

    RECORD(TPM2_IN, PCR_Read) * tpm2_input;
    RECORD(TPM2_OUT, PCR_Read) * tpm2_output;
    tpm2_input = Talloc0(sizeof(*tpm2_input));
    if (tpm2_input == NULL)
        return -ENOMEM;
    tpm2_output = Talloc0(sizeof(*tpm2_output));
    if (tpm2_output == NULL)
        return -ENOMEM;

    struct tpm2_utils_input *input_para = para; //定义输入参数
    char *index_para;
    char *value_para;
    if ((input_para->param_num > 0) && (input_para->param_num % 2 == 1)) //余1是什么意思
    {
        for (i = 1; i < input_para->param_num; i += 2)
        {
            index_para = input_para->params + i * DIGEST_SIZE;
            value_para = index_para + DIGEST_SIZE; // input_para->params==pcrread   index_para=-ix   value_para=2 ？？
            if (!Strcmp("-ix", index_para))        // in:  pcrread -ix 2 -wf pcrfile
            {
                sscanf(value_para, "%x", &pcrIndex); // tpm2_input->pcrIndex未定义？
            }
            else if (!Strcmp("-wf", index_para))
            {
                pcrfile = value_para;
            }
            else
            {
                printf("Error cmd format! should be %s -ix pcrindex -wf pcrfile", input_para->params);
                return -EINVAL;
            }
        }
    }
    //输入消息初始化
    tpm2_input->tag = TPM_ST_SESSIONS;
    tpm2_input->commandCode = TPM_CC_PCR_Read;
    tpm2_input->pcrSelectionIn.count = 1;                                                                              //指定pcr查询列表中的pcr种类数，根据hash划分？？？？
    tpm2_input->pcrSelectionIn.pcrSelections = Talloc0(sizeof(TPMS_PCR_SELECTION) * tpm2_input->pcrSelectionIn.count); //为pcr列表开辟空间,TPMS_PCR_SELECTION
    tpm2_input->pcrSelectionIn.pcrSelections[0].hash = TPM_ALG_SM3_256;                                                //采用的哈希函数
    tpm2_input->pcrSelectionIn.pcrSelections[0].sizeofSelect = 3;                                                      // pcrSelect数组中的八位字节个数，24个pcr需要3个八位字节
    // tpm2_input->pcrSelectionIn.pcrSelections[0].pcrSelect=(char *)Talloc0(tpm2_input->pcrSelectionIn.pcrSelections[0].sizeofSelect*sizeof(char)); /**为pcr查询数组开辟空间**/
    tpm2_input->pcrSelectionIn.pcrSelections[0].pcrSelect = Talloc0(tpm2_input->pcrSelectionIn.pcrSelections[0].sizeofSelect);  //为pcr查询数组开辟空间
    Memset(tpm2_input->pcrSelectionIn.pcrSelections[0].pcrSelect, 0, tpm2_input->pcrSelectionIn.pcrSelections[0].sizeofSelect); //初始化查询数组 三个八位字节全部为0
    // pcrSelect[0]&=0x01;/**如何将想要读取的pcr号对应的位赋值为1？？？位图置位函数在cube-1.3/cubelib/include/memfunc.h里**/
    bitmap_set(tpm2_input->pcrSelectionIn.pcrSelections[0].pcrSelect, pcrIndex); /**将pcr下标对应的位赋值为1**/
    // int bitmap_clear(BYTE * bitmap,int site);
    // int bitmap_get(BYTE * bitmap,int site);
    // int bitmap_is_allset(BYTE * bitmap,int size);
    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_IN, PCR_Read)); //获取tpm2_input的模板，用模板直接实现结构的序列化。
    if (tpm2_template == NULL)
        return -EINVAL;
    tpm2_input->commandSize = sizeof(*tpm2_input);

    cmdsize = struct_2_blob(tpm2_input, Buf, tpm2_template); //消息序列化
    if (cmdsize < 0)
        return cmdsize;
    tpm2_input->commandSize = cmdsize;

    *(int *)(Buf + sizeof(tpm2_input->tag)) = htonl(cmdsize); //将主机字节顺序转换为网络字节顺序

    printf("Send command for PCR_Read:\n");
    print_bin_data(Buf, cmdsize, 8); //以16进制显示发送的二进制消息

    ret = tpm2utils_transmit(cmdsize, Buf, &outlen, Buf); //通过通道与驱动对接，到达模拟器，最终与pcr模块传输数据
    if (ret < 0)
        return ret;

    printf("Receive  output is:\n");
    print_bin_data(Buf, outlen, 8); //以16进制显示接受的二进制消息

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, PCR_Read));
    //  struct_read_elem_text("randomBytes.buffer",tpm2_output,Output,tpm2_template);
    sprintf(Buf, "%d %d\n", tpm2_output->responseCode, tpm2_output->pcrUpdateCounter);
    printf("Output para: %s\n", Buf);
    void *send_msg = tpm2_auto_build_outputmsg(Buf, curr_recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;

    return 0;
}

int proc_tpm2utils_Object_CreatePrimary(void *sub_proc, void *para)
{
    printf("proc_tpm2utils_Object_CreatePrimary start :\n");
    int outlen;
    int i = 0;
    int ret = 0;
    int cmdsize = 0;
    int pcrIndex;
    void *tpm2_template;
    char *pcrfile;
    int is_ibm_emulator = 0;

    RECORD(TPM2_IN, CreatePrimary) * tpm2_input;
    RECORD(TPM2_OUT, CreatePrimary) * tpm2_output;
    tpm2_input = Talloc0(sizeof(*tpm2_input));
    if (tpm2_input == NULL)
        return -ENOMEM;
    tpm2_output = Talloc0(sizeof(*tpm2_output));
    if (tpm2_output == NULL)
        return -ENOMEM;

    struct tpm2_utils_input *input_para = para; //定义输入参数
    char *index_para;
    char *value_para;
    if ((input_para->param_num > 0) && (input_para->param_num % 2 == 1)) //余1是什么意思
    {
        for (i = 1; i < input_para->param_num; i += 2)
        {
            index_para = input_para->params + i * DIGEST_SIZE;
            value_para = index_para + DIGEST_SIZE; // input_para->params==pcrread   index_para=-ix   value_para=2 ？？
            if (!Strcmp("-ix", index_para))        // in: createPrimary -ix 2 -wf pcrfile
            {
                sscanf(value_para, "%x", &pcrIndex); // tpm2_input->pcrIndex未定义？
            }
            else if (!Strcmp("-wf", index_para))
            {
                pcrfile = value_para;
            }
            else if (!Strcmp("-ibm", index_para))       // in: createPrimary -ibm 1 -ix 2 -wf pcrfile
            {
                sscanf(value_para, "%u", &is_ibm_emulator); // -ibm ： 对应是否调用ibm模拟器，默认为0，false。调用为 1 ，true。
            }
            else
            {
                printf("Error cmd format! should be %s -ix pcrindex -wf pcrfile", input_para->params);
                return -EINVAL;
            }
        }
    }
    //输入消息初始化
    //对命令基本信息初始化
    tpm2_input->tag = TPM_ST_SESSIONS;
    tpm2_input->commandCode = TPM_CC_CreatePrimary;

    //对primaryHandle初始化. TPM_CreatePrimary命令用于在一个主种子下创建一个主对象，或在TPM_RH_NULL下创建一个临时对象。
    tpm2_input->primaryHandle = TPM_RH_NULL;

    //对公共模板inPublic初始化
    tpm2_input->inPublic.publicArea.type = TPM_ALG_ECC; //  先采用类型为：TPM_ALG_ECC椭圆曲线加密算法SM2
    //  -----   参考 part3_Commands : 12.1.1  b)  If the Object is an asymmetric key:
    tpm2_input->inPublic.publicArea.nameAlg = TPM_ALG_SM2; // nameAlg 设置为 SM2 非对称秘钥
    //  -----   对于TPMA_OBJECT类型的 objectAttributes来说：
    //  -----   如果调用者表示他们已经提供了数据，那么要确保他们已经提供了一些数据。
    //  -----   当'sensitive.data'是一个空缓冲区时，sensitiveDataOrigin是CLEAR，或者当'sensitive.data'不是空的时候是SET。
    //  -----   对于普通对象来说，只有当sensitiveDataOrigin为CLEAR时才能提供数据。
    //  -----   Asymmetric keys cannot have the sensitive portion provided. 非对称秘钥不能提供敏感部分。The inSensitive.sensitive.data.size parameter  is  required  to  be  zero  for  an  asymmetric  key  so sensitiveDataOrigin is required to be SET.
    // TODO: objectAttributes属性设置
#if USE_BIT_FIELD_STRUCTURES
    tpm2_input->inPublic.publicArea.objectAttributes.sensitiveDataOrigin = CLEAR;
#else  // USE_BIT_FIELD_STRUCTURES
    tpm2_input->inPublic.publicArea.objectAttributes = TPMA_ZERO_INITIALIZER();
    // tpm2_input->inPublic.publicArea.objectAttributes = TPMA_OBJECT_INITIALIZER(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, fixedTPM);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, stClear);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, fixedParent);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, sensitiveDataOrigin);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, userWithAuth);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, noDA);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, encryptedDuplication);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, restricted); // 如果模板中没有SET sign 和 decrypt，则模板中应为CLEAR。
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, decrypt);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, sign); // shall not be SET if decrypt and restricted are both SET
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, x509sign);
#endif // USE_BIT_FIELD_STRUCTURES

    //  -----   对 authPolicy 初始化
    // TODO: authPolicy
    tpm2_input->inPublic.publicArea.authPolicy.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.authPolicy.b.size = 0;
    //  -----   对 parameters 初始化
    //  -----   parameters参数中，若type为 TPM_ALG_ECC ，设置parameters.eccDetaill
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.mode.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_SM2;
    // TODO: .sm2.hashAlg
    tpm2_input->inPublic.publicArea.parameters.eccDetail.scheme.details.sm2.hashAlg = TPM_ALG_SM2;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_SM2_P256;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; // 目前没有任何命令可以让调用者指定用于ECC解密密钥的KDF。由于没有使用这种能力，参考实现要求将模板中的kdf设置为TPM_ALG_NULL，否则将返回TPM_RC_KDF。
    // kdf设置为TPM_ALG_NULL，detail没有设置
    // tpm2_input->inPublic.publicArea.parameters.eccDetail.kdf.details.kdf1_sp800_56a.hashAlg = TPM_ALG_SM2;
    //  -----   parameters参数中，若type为 TPM_ALG_ECC ，设置parameters.asymDetail
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.algorithm = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.keyBits.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.mode.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.scheme = TPM_ALG_SM2;
    // TODO: .sm2.hashAlg
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.details.sm2.hashAlg = TPM_ALG_SM2;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.details.anySig.hashAlg = TPM_ALG_SM2;
    // TODO: unique
    tpm2_input->inPublic.publicArea.unique.keyedHash.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.keyedHash.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.sym.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.sym.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.ecc.x.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.ecc.x.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.ecc.y.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.ecc.y.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.derive.label.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.derive.label.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.derive.context.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.derive.context.b.buffer = NULL;

    tpm2_input->inPublic.size = sizeof(tpm2_input->inPublic.publicArea);

    //对敏感区域inSensitive初始化
    // userAuth USER认证的秘密值
    tpm2_input->inSensitive.sensitive.userAuth.b.buffer = NULL;
    tpm2_input->inSensitive.sensitive.userAuth.b.size = 0;
    tpm2_input->inSensitive.sensitive.data.b.buffer = NULL;
    tpm2_input->inSensitive.sensitive.data.b.size = 0;
    // 敏感字节的大小(可能不是零)。这个缓冲区中的userAuth和data参数可能都是零长度，但这个参数的最小大小将是TPMS_SENSITIVE_CREATE的两个参数的size字段的和。
    tpm2_input->inSensitive.size = tpm2_input->inSensitive.sensitive.userAuth.b.size + tpm2_input->inSensitive.sensitive.data.b.size;
    // tpm2_input->inSensitive.size = sizeof(tpm2_input->inSensitive.sensitive);

    // 对创建数据 outsideInfo 初始化
    tpm2_input->outsideInfo.b.buffer = NULL;
    tpm2_input->outsideInfo.b.size = 0;

    //对creationPCR初始化
    tpm2_input->creationPCR.count = 1;                                                                           //指定pcr查询列表中的pcr种类数，根据hash划分
    tpm2_input->creationPCR.pcrSelections = Talloc0(sizeof(TPMS_PCR_SELECTION) * tpm2_input->creationPCR.count); //为pcr列表开辟空间,TPMS_PCR_SELECTION
    tpm2_input->creationPCR.pcrSelections[0].hash = TPM_ALG_SM3_256;                                             //采用的哈希函数
    tpm2_input->creationPCR.pcrSelections[0].sizeofSelect = 3;                                                   // pcrSelect数组中的八位字节个数，24个pcr需要3个八位字节
    // tpm2_input->creationPCR.pcrSelections[0].pcrSelect=(char *)Talloc0(tpm2_input->creationPCR.pcrSelections[0].sizeofSelect*sizeof(char)); /**为pcr查询数组开辟空间**/
    tpm2_input->creationPCR.pcrSelections[0].pcrSelect = Talloc0(sizeof(BYTE) * tpm2_input->creationPCR.pcrSelections[0].sizeofSelect); //为pcr查询数组开辟空间
    Memset(tpm2_input->creationPCR.pcrSelections[0].pcrSelect, 0, tpm2_input->creationPCR.pcrSelections[0].sizeofSelect);               //初始化查询数组 三个八位字节全部为0
    // pcrSelect[0]&=0x01;/**如何将想要读取的pcr号对应的位赋值为1？？？位图置位函数在cube-1.3/cubelib/include/memfunc.h里**/
    bitmap_set(tpm2_input->creationPCR.pcrSelections[0].pcrSelect, pcrIndex); /**将pcr下标对应的位赋值为1**/

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_IN, CreatePrimary)); //获取tpm2_input的模板，用模板直接实现结构的序列化。
    if (tpm2_template == NULL)
    {
        return -EINVAL;
    }
    tpm2_input->commandSize = sizeof(*tpm2_input);

    //开始消息序列化commandSize
    cmdsize = struct_2_blob(tpm2_input, Buf, tpm2_template);
    if (cmdsize < 0)
    {
        return cmdsize;
    }
    //重新设置消息序列化后的commandSize
    tpm2_input->commandSize = cmdsize;

    //将主机字节顺序转换为网络字节顺序
    *(int *)(Buf + sizeof(tpm2_input->tag)) = htonl(cmdsize);

    printf("Send command for CreatePrimary:\n");
    print_bin_data(Buf, cmdsize, 8); //以16进制显示发送的二进制命令消息

    // 是否调用ibm tpm2 模拟器，默认为 0 ，false。
    if (is_ibm_emulator)
    {
        // 调用ibm tpm2 模拟器执行请求命令。 将请求命令输入到二进制文件中。二进制文件默认生成在/cube-tpm2/instance/tpm2_utils目录中
        outlen = tpm2utils_ex_ibmtpm2_emulator(ret, "/root/centoscloud/cube-tpm2/instance/tpm2_utils/object_commands/tpm2_send_createprimary_cmd.sh", "tpm2_cmd_createprimary.bin", "tpm2_response_createprimary.bin");
    }
    else
    {
        // 调用自己的 tpm2 模拟器执行请求命令。通过通道与驱动对接，到达模拟器，
        ret = tpm2utils_transmit(cmdsize, Buf, &outlen, Buf);
    }
    if (ret < 0)
        return ret;

    printf("Receive  output is:\n");
    print_bin_data(Buf, outlen, 8); //以16进制显示接受的二进制响应消息

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, CreatePrimary));
    //  struct_read_elem_text("randomBytes.buffer",tpm2_output,Output,tpm2_template);
    sprintf(Buf, "%d %d\n", tpm2_output->responseCode, tpm2_output->name);
    printf("Output para: %s\n", Buf);
    void *send_msg = tpm2_auto_build_outputmsg(Buf, curr_recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;

    return 0;
}

// Non primary keys are created with the TPM2_CC_Create command. The command takes as input a handle to the parent key, and the key's TPM2B_PUBLIC template
// 非主键是用Create命令创建的。该命令将父密钥的句柄和密钥的 TPM2B_PUBLIC 模板作为输入。参考 https://google.github.io/tpm-js/#pg_keys
// TPM2_CC_Create creates but doesn't load the key onto the TPM. The command returns TPM2B_PRIVATE which is the key material wrapped (encrypted) by the parent key. Use TPM2_CC_Load to load the key onto the TPM.
// Create 创建但不将密钥加载到 TPM。该命令返回 TPM2B_PRIVATE 哪个是由父密钥包装（加密）的密钥材料。用于_Load将密钥加载到 TPM。
// 注意：Create 通过 CreatePrimary 创建的对象返回的句柄和密钥来创建的对象，其父对象名字应该和 CreatePrimary 创建的对象名字相同
int proc_tpm2utils_Object_Create(void *sub_proc, void *para)
{
    printf("proc_tpm2utils_Object_Create start :\n");
    int outlen;
    int i = 0;
    int ret = 0;
    int cmdsize = 0;
    int pcrIndex;
    void *tpm2_template;
    char *pcrfile;

    RECORD(TPM2_IN, Create) * tpm2_input;
    RECORD(TPM2_OUT, Create) * tpm2_output;
    tpm2_input = Talloc0(sizeof(*tpm2_input));
    if (tpm2_input == NULL)
        return -ENOMEM;
    tpm2_output = Talloc0(sizeof(*tpm2_output));
    if (tpm2_output == NULL)
        return -ENOMEM;

    struct tpm2_utils_input *input_para = para; //定义输入参数
    char *index_para;
    char *value_para;
    if ((input_para->param_num > 0) && (input_para->param_num % 2 == 1)) //余1是什么意思
    {
        for (i = 1; i < input_para->param_num; i += 2)
        {
            index_para = input_para->params + i * DIGEST_SIZE;
            value_para = index_para + DIGEST_SIZE; // input_para->params==pcrread   index_para=-ix   value_para=2 ？？
            if (!Strcmp("-ix", index_para))        // in:  pcrread -ix 2 -wf pcrfile
            {
                sscanf(value_para, "%x", &pcrIndex); // tpm2_input->pcrIndex未定义？
            }
            else if (!Strcmp("-wf", index_para))
            {
                pcrfile = value_para;
            }
            else
            {
                printf("Error cmd format! should be %s -ix pcrindex -wf pcrfile", input_para->params);
                return -EINVAL;
            }
        }
    }
    //输入消息初始化
    //对命令基本信息初始化
    tpm2_input->tag = TPM_ST_SESSIONS;
    tpm2_input->commandCode = TPM_CC_Create;

    //对primaryHandle初始化
    tpm2_input->parentHandle = TPM_RH_NULL;

    //对公共模板inPublic初始化
    tpm2_input->inPublic.publicArea.type = TPM_ALG_ECC; //  先采用类型为：TPM_ALG_ECC椭圆曲线加密算法SM2
    //  -----   参考 part3_Commands : 12.1.1  b)  If the Object is an asymmetric key:
    tpm2_input->inPublic.publicArea.nameAlg = TPM_ALG_SM2; // nameAlg 设置为 SM2 非对称秘钥
    //  -----   对于TPMA_OBJECT类型的 objectAttributes来说：
    //  -----   如果调用者表示他们已经提供了数据，那么要确保他们已经提供了一些数据。
    //  -----   当'sensitive.data'是一个空缓冲区时，sensitiveDataOrigin是CLEAR，或者当'sensitive.data'不是空的时候是SET。
    //  -----   对于普通对象来说，只有当sensitiveDataOrigin为CLEAR时才能提供数据。
    //  -----   Asymmetric keys cannot have the sensitive portion provided. 非对称秘钥不能提供敏感部分。
    // TODO: objectAttributes属性
#if USE_BIT_FIELD_STRUCTURES
    tpm2_input->inPublic.publicArea.objectAttributes.sensitiveDataOrigin = CLEAR;
#else  // USE_BIT_FIELD_STRUCTURES
    tpm2_input->inPublic.publicArea.objectAttributes = TPMA_ZERO_INITIALIZER();
    // tpm2_input->inPublic.publicArea.objectAttributes = TPMA_OBJECT_INITIALIZER(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, fixedTPM);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, stClear);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, fixedParent);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, sensitiveDataOrigin);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, userWithAuth);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, noDA);
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, encryptedDuplication);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, restricted); // 如果模板中没有SET sign 和 decrypt，则模板中应为CLEAR。
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, decrypt);
    SET_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, sign); // shall not be SET if decrypt and restricted are both SET
    CLEAR_ATTRIBUTE(tpm2_input->inPublic.publicArea.objectAttributes, TPMA_OBJECT, x509sign);
#endif // USE_BIT_FIELD_STRUCTURES
    //  -----   对 authPolicy 初始化
    // TODO: authPolicy
    tpm2_input->inPublic.publicArea.authPolicy.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.authPolicy.b.size = 0;
    //  -----   对 parameters 初始化
    //  -----   parameters参数中，若type为 TPM_ALG_ECC ，设置parameters.eccDetaill
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.symmetric.mode.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_SM2;
    // TODO: .sm2.hashAlg
    tpm2_input->inPublic.publicArea.parameters.eccDetail.scheme.details.sm2.hashAlg = TPM_ALG_SM2;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_SM2_P256;
    tpm2_input->inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; // 目前没有任何命令可以让调用者指定用于ECC解密密钥的KDF。由于没有使用这种能力，参考实现要求将模板中的kdf设置为TPM_ALG_NULL，否则将返回TPM_RC_KDF。
    // kdf设置为TPM_ALG_NULL，detail没有设置
    // tpm2_input->inPublic.publicArea.parameters.eccDetail.kdf.details.kdf1_sp800_56a.hashAlg = TPM_ALG_SM2;
    //  -----   parameters参数中，若type为 TPM_ALG_ECC ，设置parameters.asymDetail
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.algorithm = TPM_ALG_SM4;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.keyBits.sym = 128;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.symmetric.mode.sym = TPM_ALG_NULL;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.scheme = TPM_ALG_SM2;
    // TODO: .sm2.hashAlg
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.details.sm2.hashAlg = TPM_ALG_SM2;
    tpm2_input->inPublic.publicArea.parameters.asymDetail.scheme.details.anySig.hashAlg = TPM_ALG_SM2;
    // TODO: unique
    tpm2_input->inPublic.publicArea.unique.keyedHash.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.keyedHash.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.sym.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.sym.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.ecc.x.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.ecc.x.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.ecc.y.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.ecc.y.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.derive.label.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.derive.label.b.buffer = NULL;
    tpm2_input->inPublic.publicArea.unique.derive.context.b.size = 0;
    tpm2_input->inPublic.publicArea.unique.derive.context.b.buffer = NULL;

    tpm2_input->inPublic.size = sizeof(tpm2_input->inPublic.publicArea);

    //对敏感区域inSensitive初始化
    // userAuth USER认证的秘密值
    tpm2_input->inSensitive.sensitive.userAuth.b.buffer = NULL;
    tpm2_input->inSensitive.sensitive.userAuth.b.size = 0;
    tpm2_input->inSensitive.sensitive.data.b.buffer = NULL;
    tpm2_input->inSensitive.sensitive.data.b.size = 0;
    // 敏感字节的大小(可能不是零)。这个缓冲区中的userAuth和data参数可能都是零长度，但这个参数的最小大小将是TPMS_SENSITIVE_CREATE的两个参数的size字段的和。
    tpm2_input->inSensitive.size = tpm2_input->inSensitive.sensitive.userAuth.b.size + tpm2_input->inSensitive.sensitive.data.b.size;
    // tpm2_input->inSensitive.size = sizeof(tpm2_input->inSensitive.sensitive);

    // 对创建数据 outsideInfo 初始化
    tpm2_input->outsideInfo.b.buffer = NULL;
    tpm2_input->outsideInfo.b.size = 0;

    //对creationPCR初始化
    tpm2_input->creationPCR.count = 1;                                                                           //指定pcr查询列表中的pcr种类数，根据hash划分？？？？
    tpm2_input->creationPCR.pcrSelections = Talloc0(sizeof(TPMS_PCR_SELECTION) * tpm2_input->creationPCR.count); //为pcr列表开辟空间,TPMS_PCR_SELECTION
    tpm2_input->creationPCR.pcrSelections[0].hash = TPM_ALG_SM3_256;                                             //采用的哈希函数
    tpm2_input->creationPCR.pcrSelections[0].sizeofSelect = 3;                                                   // pcrSelect数组中的八位字节个数，24个pcr需要3个八位字节
    // tpm2_input->creationPCR.pcrSelections[0].pcrSelect=(char *)Talloc0(tpm2_input->creationPCR.pcrSelections[0].sizeofSelect*sizeof(char)); /**为pcr查询数组开辟空间**/
    tpm2_input->creationPCR.pcrSelections[0].pcrSelect = Talloc0(sizeof(BYTE) * tpm2_input->creationPCR.pcrSelections[0].sizeofSelect); //为pcr查询数组开辟空间
    Memset(tpm2_input->creationPCR.pcrSelections[0].pcrSelect, 0, tpm2_input->creationPCR.pcrSelections[0].sizeofSelect);               //初始化查询数组 三个八位字节全部为0
    // pcrSelect[0]&=0x01;/**如何将想要读取的pcr号对应的位赋值为1？？？位图置位函数在cube-1.3/cubelib/include/memfunc.h里**/
    bitmap_set(tpm2_input->creationPCR.pcrSelections[0].pcrSelect, pcrIndex); /**将pcr下标对应的位赋值为1**/
    // int bitmap_clear(BYTE * bitmap,int site);
    // int bitmap_get(BYTE * bitmap,int site);
    // int bitmap_is_allset(BYTE * bitmap,int size);
    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_IN, Create)); //获取tpm2_input的模板，用模板直接实现结构的序列化。
    if (tpm2_template == NULL)
    {
        return -EINVAL;
    }
    tpm2_input->commandSize = sizeof(*tpm2_input);

    //开始消息序列化commandSize
    cmdsize = struct_2_blob(tpm2_input, Buf, tpm2_template);
    if (cmdsize < 0)
        return cmdsize;
    //重新设置消息序列化后的commandSize
    tpm2_input->commandSize = cmdsize;

    //将主机字节顺序转换为网络字节顺序
    *(int *)(Buf + sizeof(tpm2_input->tag)) = htonl(cmdsize);

    printf("Send command for Create:\n");
    print_bin_data(Buf, cmdsize, 8); //以16进制显示发送的二进制命令消息

    //通过通道与驱动对接，到达模拟器，最终与pcr模块传输数据
    ret = tpm2utils_transmit(cmdsize, Buf, &outlen, Buf);
    if (ret < 0)
        return ret;

    printf("Receive  output is:\n");
    print_bin_data(Buf, outlen, 8); //以16进制显示接受的二进制响应消息

    tpm2_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, Create));
    //  struct_read_elem_text("randomBytes.buffer",tpm2_output,Output,tpm2_template);
    sprintf(Buf, "%d %d\n", tpm2_output->responseCode, tpm2_output->creationHash);
    printf("Output para: %s\n", Buf);
    void *send_msg = tpm2_auto_build_outputmsg(Buf, curr_recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;

    return 0;
}

int tpm2utils_transmit(int in_len, BYTE *in, int *out_len, BYTE *out)
{
    int ret;
    ret = channel_write(tpm2_caller, in, in_len); //没有channel模块的api
    if (ret != in_len)
        return -EINVAL;
    for (;;)
    {
        usleep(time_val.tv_usec);
        ret = channel_read(tpm2_caller, out, DIGEST_SIZE * 32);
        if (ret < 0)
            return ret;
        if (ret > 0)
        {
            *out_len = ret;
            break;
        }
    }

    return ret;
}

// 将请求命令输入到二进制文件中
int tpm2utils_bytes2binfile(int *ret, char *cmdfilename)
{
    // 将请求命令输入到二进制文件中
    printf("Write bytes to bin file %s start !\n", cmdfilename);
    int fd;
    fd = open(cmdfilename, O_WRONLY | O_CREAT | O_TRUNC);
    if (fd < 0)
    {
        printf("open failed!\n");
        return fd;
    }
    write(fd, Buf, ret);
    close(fd);

    printf("Receive bytes write to bin file end ! \n");
}

//  读取命令返回的二进制文件
int tpm2utils_binfile2bytes(int *ret, char *responsefilename)
{
    //读取命令返回的二进制文件
    printf("Read bin file %s to bytes start !\n", responsefilename);
    FILE *file = fopen(responsefilename, "rb");
    if (file == NULL)
    {
        printf("open responsefile name error\n");
        return -EINVAL;
    }
    int size = fread(Buf, 32 * 32, 1, file);
    fclose(file);
    printf("Read bin file to bytes end ! \n");
    return size;
}

// 调用ibm tpm2 模拟器,发送执行命令，并将返回结果。
int tpm2utils_ex_ibmtpm2_emulator(int *ret, char *shellcmd, char *cmdfilename, char *responsefilename)
{
    int outlen;
    printf("Execute ibmtpm2 emulator start !\n");
    // 将请求命令输入到二进制文件中
    tpm2utils_bytes2binfile(ret, cmdfilename);
    // 执行脚本命令
    system(shellcmd);
    // system("tpm2_send_getrandom_cmd.sh");

    // 将ibm模拟器命令返回的二进制文件转换为字节流
    outlen = tpm2utils_binfile2bytes(ret, responsefilename);

    printf("Execute ibmtpm2 emulator end !\n");
    return outlen;
}